/*
 *
 *
 *
 *                                   Apache License
 *                             Version 2.0, January 2004
 *                          http://www.apache.org/licenses/
 *
 *     TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
 *
 *     1. Definitions.
 *
 *        "License" shall mean the terms and conditions for use, reproduction,
 *        and distribution as defined by Sections 1 through 9 of this document.
 *
 *        "Licensor" shall mean the copyright owner or entity authorized by
 *        the copyright owner that is granting the License.
 *
 *        "Legal Entity" shall mean the union of the acting entity and all
 *        other entities that control, are controlled by, or are under common
 *        control with that entity. For the purposes of this definition,
 *        "control" means (i) the power, direct or indirect, to cause the
 *        direction or management of such entity, whether by contract or
 *        otherwise, or (ii) ownership of fifty percent (50%) or more of the
 *        outstanding shares, or (iii) beneficial ownership of such entity.
 *
 *        "You" (or "Your") shall mean an individual or Legal Entity
 *        exercising permissions granted by this License.
 *
 *        "Source" form shall mean the preferred form for making modifications,
 *        including but not limited to software source code, documentation
 *        source, and configuration files.
 *
 *        "Object" form shall mean any form resulting from mechanical
 *        transformation or translation of a Source form, including but
 *        not limited to compiled object code, generated documentation,
 *        and conversions to other media types.
 *
 *        "Work" shall mean the work of authorship, whether in Source or
 *        Object form, made available under the License, as indicated by a
 *        copyright notice that is included in or attached to the work
 *        (an example is provided in the Appendix below).
 *
 *        "Derivative Works" shall mean any work, whether in Source or Object
 *        form, that is based on (or derived from) the Work and for which the
 *        editorial revisions, annotations, elaborations, or other modifications
 *        represent, as a whole, an original work of authorship. For the purposes
 *        of this License, Derivative Works shall not include works that remain
 *        separable from, or merely link (or bind by name) to the interfaces of,
 *        the Work and Derivative Works thereof.
 *
 *        "Contribution" shall mean any work of authorship, including
 *        the original version of the Work and any modifications or additions
 *        to that Work or Derivative Works thereof, that is intentionally
 *        submitted to Licensor for inclusion in the Work by the copyright owner
 *        or by an individual or Legal Entity authorized to submit on behalf of
 *        the copyright owner. For the purposes of this definition, "submitted"
 *        means any form of electronic, verbal, or written communication sent
 *        to the Licensor or its representatives, including but not limited to
 *        communication on electronic mailing lists, source code control systems,
 *        and issue tracking systems that are managed by, or on behalf of, the
 *        Licensor for the purpose of discussing and improving the Work, but
 *        excluding communication that is conspicuously marked or otherwise
 *        designated in writing by the copyright owner as "Not a Contribution."
 *
 *        "Contributor" shall mean Licensor and any individual or Legal Entity
 *        on behalf of whom a Contribution has been received by Licensor and
 *        subsequently incorporated within the Work.
 *
 *     2. Grant of Copyright License. Subject to the terms and conditions of
 *        this License, each Contributor hereby grants to You a perpetual,
 *        worldwide, non-exclusive, no-charge, royalty-free, irrevocable
 *        copyright license to reproduce, prepare Derivative Works of,
 *        publicly display, publicly perform, sublicense, and distribute the
 *        Work and such Derivative Works in Source or Object form.
 *
 *     3. Grant of Patent License. Subject to the terms and conditions of
 *        this License, each Contributor hereby grants to You a perpetual,
 *        worldwide, non-exclusive, no-charge, royalty-free, irrevocable
 *        (except as stated in this section) patent license to make, have made,
 *        use, offer to sell, sell, import, and otherwise transfer the Work,
 *        where such license applies only to those patent claims licensable
 *        by such Contributor that are necessarily infringed by their
 *        Contribution(s) alone or by combination of their Contribution(s)
 *        with the Work to which such Contribution(s) was submitted. If You
 *        institute patent litigation against any entity (including a
 *        cross-claim or counterclaim in a lawsuit) alleging that the Work
 *        or a Contribution incorporated within the Work constitutes direct
 *        or contributory patent infringement, then any patent licenses
 *        granted to You under this License for that Work shall terminate
 *        as of the date such litigation is filed.
 *
 *     4. Redistribution. You may reproduce and distribute copies of the
 *        Work or Derivative Works thereof in any medium, with or without
 *        modifications, and in Source or Object form, provided that You
 *        meet the following conditions:
 *
 *        (a) You must give any other recipients of the Work or
 *            Derivative Works a copy of this License; and
 *
 *        (b) You must cause any modified files to carry prominent notices
 *            stating that You changed the files; and
 *
 *        (c) You must retain, in the Source form of any Derivative Works
 *            that You distribute, all copyright, patent, trademark, and
 *            attribution notices from the Source form of the Work,
 *            excluding those notices that do not pertain to any part of
 *            the Derivative Works; and
 *
 *        (d) If the Work includes a "NOTICE" text file as part of its
 *            distribution, then any Derivative Works that You distribute must
 *            include a readable copy of the attribution notices contained
 *            within such NOTICE file, excluding those notices that do not
 *            pertain to any part of the Derivative Works, in at least one
 *            of the following places: within a NOTICE text file distributed
 *            as part of the Derivative Works; within the Source form or
 *            documentation, if provided along with the Derivative Works; or,
 *            within a display generated by the Derivative Works, if and
 *            wherever such third-party notices normally appear. The contents
 *            of the NOTICE file are for informational purposes only and
 *            do not modify the License. You may add Your own attribution
 *            notices within Derivative Works that You distribute, alongside
 *            or as an addendum to the NOTICE text from the Work, provided
 *            that such additional attribution notices cannot be construed
 *            as modifying the License.
 *
 *        You may add Your own copyright statement to Your modifications and
 *        may provide additional or different license terms and conditions
 *        for use, reproduction, or distribution of Your modifications, or
 *        for any such Derivative Works as a whole, provided Your use,
 *        reproduction, and distribution of the Work otherwise complies with
 *        the conditions stated in this License.
 *
 *     5. Submission of Contributions. Unless You explicitly state otherwise,
 *        any Contribution intentionally submitted for inclusion in the Work
 *        by You to the Licensor shall be under the terms and conditions of
 *        this License, without any additional terms or conditions.
 *        Notwithstanding the above, nothing herein shall supersede or modify
 *        the terms of any separate license agreement you may have executed
 *        with Licensor regarding such Contributions.
 *
 *     6. Trademarks. This License does not grant permission to use the trade
 *        names, trademarks, service marks, or product names of the Licensor,
 *        except as required for reasonable and customary use in describing the
 *        origin of the Work and reproducing the content of the NOTICE file.
 *
 *     7. Disclaimer of Warranty. Unless required by applicable law or
 *        agreed to in writing, Licensor provides the Work (and each
 *        Contributor provides its Contributions) on an "AS IS" BASIS,
 *        WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
 *        implied, including, without limitation, any warranties or conditions
 *        of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
 *        PARTICULAR PURPOSE. You are solely responsible for determining the
 *        appropriateness of using or redistributing the Work and assume any
 *        risks associated with Your exercise of permissions under this License.
 *
 *     8. Limitation of Liability. In no event and under no legal theory,
 *        whether in tort (including negligence), contract, or otherwise,
 *        unless required by applicable law (such as deliberate and grossly
 *        negligent acts) or agreed to in writing, shall any Contributor be
 *        liable to You for damages, including any direct, indirect, special,
 *        incidental, or consequential damages of any character arising as a
 *        result of this License or out of the use or inability to use the
 *        Work (including but not limited to damages for loss of goodwill,
 *        work stoppage, computer failure or malfunction, or any and all
 *        other commercial damages or losses), even if such Contributor
 *        has been advised of the possibility of such damages.
 *
 *     9. Accepting Warranty or Additional Liability. While redistributing
 *        the Work or Derivative Works thereof, You may choose to offer,
 *        and charge a fee for, acceptance of support, warranty, indemnity,
 *        or other liability obligations and/or rights consistent with this
 *        License. However, in accepting such obligations, You may act only
 *        on Your own behalf and on Your sole responsibility, not on behalf
 *        of any other Contributor, and only if You agree to indemnify,
 *        defend, and hold each Contributor harmless for any liability
 *        incurred by, or claims asserted against, such Contributor by reason
 *        of your accepting any such warranty or additional liability.
 *
 *     END OF TERMS AND CONDITIONS
 *
 *     APPENDIX: How to apply the Apache License to your work.
 *
 *        To apply the Apache License to your work, attach the following
 *        boilerplate notice, with the fields enclosed by brackets "[]"
 *        replaced with your own identifying information. (Don't include
 *        the brackets!)  The text should be enclosed in the appropriate
 *        comment syntax for the file format. We also recommend that a
 *        file or class name and description of purpose be included on the
 *        same "printed page" as the copyright notice for easier
 *        identification within third-party archives.
 *
 *     Copyright 2016 Alibaba Group
 *
 *     Licensed under the Apache License, Version 2.0 (the "License");
 *     you may not use this file except in compliance with the License.
 *     You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 *     Unless required by applicable law or agreed to in writing, software
 *     distributed under the License is distributed on an "AS IS" BASIS,
 *     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *     See the License for the specific language governing permissions and
 *     limitations under the License.
 *
 *
 */

package com.taobao.android.builder.tools.proguard;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.android.build.gradle.api.BaseVariantOutput;
import com.android.build.gradle.internal.ApkDataUtils;
import com.android.build.gradle.internal.api.AppVariantContext;
import com.android.build.gradle.internal.api.AppVariantOutputContext;
import com.android.build.gradle.internal.api.AwbTransform;
import com.android.build.gradle.internal.scope.GlobalScope;
import com.android.build.gradle.internal.scope.VariantScope;
import com.android.build.gradle.internal.transforms.ProGuardTransform;
import com.android.builder.model.AndroidLibrary;
import com.google.common.base.Joiner;
import com.taobao.android.builder.AtlasBuildContext;
import com.taobao.android.builder.dependency.AtlasDependencyTree;
import com.taobao.android.builder.dependency.model.AwbBundle;
import com.taobao.android.builder.tools.Profiler;
import com.taobao.android.builder.tools.bundleinfo.BundleGraphExecutor;
import com.taobao.android.builder.tools.bundleinfo.BundleItem;
import com.taobao.android.builder.tools.bundleinfo.BundleItemRunner;
import com.taobao.android.builder.tools.bundleinfo.model.BundleInfo;
import com.taobao.android.builder.tools.proguard.domain.Input;
import com.taobao.android.builder.tools.proguard.dump.ClazzRefInfo;
import com.taobao.android.builder.tools.proguard.dump.KeepConverter;
import org.apache.commons.io.FileUtils;
import org.gradle.api.GradleException;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

import static com.android.builder.model.AndroidProject.FD_OUTPUTS;

/**
 * Created by wuzhong on 2016/12/9.
 */
public class AtlasProguardHelper {

    private static Logger sLogger = LoggerFactory.getLogger(AtlasProguardHelper.class);

    public static List<File>configs = new ArrayList<>();

    public static void doBundleProguard(final AppVariantContext appVariantContext, List<File> mainDexJars)
        throws Exception {

        Profiler.enter("preparebundleproguard");
        VariantScope variantScope = appVariantContext.getScope();
        AtlasDependencyTree dependencyTree = AtlasBuildContext.androidDependencyTrees.get(
            variantScope.getVariantConfiguration().getFullName());

        if (dependencyTree.getAwbBundles().isEmpty()) {
            return;
        }

        List<File> libs = new ArrayList<>(
            appVariantContext.getScope().getGlobalScope().getAndroidBuilder().getBootClasspath(true));

        //All dependent classes
        Profiler.enter("getDefaultClasses");
        Set<String> defaultLibClasses = getClassList(libs);
        Profiler.release();

        libs.addAll(mainDexJars);

        //Get the basic proguard configuration
        List<File> defaultProguardFiles = new ArrayList<>(

            appVariantContext.getVariantConfiguration().getBuildType().getProguardFiles());
        Collections.sort(defaultProguardFiles);

        BaseVariantOutput vod = (BaseVariantOutput) appVariantContext.getVariantOutputData().iterator().next();
        AppVariantOutputContext appVariantOutputContext = appVariantContext.getAppVariantOutputContext(ApkDataUtils.get(vod));

        int parallelCount = appVariantContext.getAtlasExtension().getTBuildConfig().getProguardParallelCount();
        ////FIXME
        //parallelCount = 1;

        Map<BundleInfo, AwbTransform> bundleInfoAwbTransformMap = new HashMap<>();
        for (AwbTransform awbTransform : appVariantOutputContext.getAwbTransformMap().values()) {
            bundleInfoAwbTransformMap.put(awbTransform.getAwbBundle().bundleInfo, awbTransform);
        }
        Profiler.release();

        BundleGraphExecutor.execute(new ArrayList<>(bundleInfoAwbTransformMap.keySet()), parallelCount,
                                    new BundleItemRunner() {
                                        @Override
                                        public void execute(BundleItem bundleItem) {

                                            try {

                                                Input input = new Input();
                                                AwbTransform awbTransform = bundleInfoAwbTransformMap.get(
                                                    bundleItem.bundleInfo);
                                                input.getAwbBundles().add(awbTransform);
                                                for (BundleInfo sub : bundleItem.circles) {
                                                    input.getAwbBundles().add(bundleInfoAwbTransformMap.get(sub));
                                                }

                                                input.getDefaultProguardFiles().addAll(defaultProguardFiles);
                                                input.getLibraries().addAll(libs);
                                                input.getDefaultLibraryClasses().addAll(defaultLibClasses);

                                                input.printConfiguration = new File(
                                                    appVariantContext
                                                        .getAwbProguardDir(input.getAwbBundles().get(0).getAwbBundle()),
                                                    "proguard.cfg");
                                                input.printUsage = new File(
                                                    appVariantContext
                                                        .getAwbProguardDir(input.getAwbBundles().get(0).getAwbBundle()),
                                                    "usage.cfg");

                                                addLibraryProguardFiles(appVariantContext, input);

                                                addChildDependency(bundleItem, input, bundleInfoAwbTransformMap);

                                                addParentKeeps(bundleItem, input, awbTransform,
                                                               bundleInfoAwbTransformMap, appVariantContext);

                                                BundleProguarder.execute(appVariantContext, input);

                                            } catch (Exception e) {
                                                e.printStackTrace();
                                                throw new GradleException(
                                                    "proguard " + bundleItem.bundleInfo.getPkgName(), e);
                                            }
                                        }
                                    });

    }

    @NotNull
    private static void addLibraryProguardFiles(AppVariantContext appVariantContext, Input input) {

        if (!appVariantContext.getAtlasExtension().getTBuildConfig().isBundleProguardConfigEnabled()) {
            return;
        }

        Set<String> blackList = appVariantContext.getAtlasExtension().getTBuildConfig()
            .getBundleProguardConfigBlackList();
        for (AwbTransform awbTransform : input.getAwbBundles()) {
            AwbBundle awbBundle = awbTransform.getAwbBundle();
            for (AndroidLibrary androidDependency : awbBundle.getAllLibraryAars()) {
                File proguardRules = androidDependency.getProguardRules();
                String groupName = androidDependency.getResolvedCoordinates().getGroupId() + ":" + androidDependency
                    .getResolvedCoordinates().getArtifactId();
                if (blackList.contains(groupName)) {
                    sLogger.info("[proguard] skip proguard from " + androidDependency.getResolvedCoordinates());
                    continue;
                }
                if (proguardRules.exists() && proguardRules.isFile()) {
                    input.getLibraryProguardFiles().add(proguardRules);
                    sLogger.warn("[proguard] load proguard from " + androidDependency.getResolvedCoordinates());
                } else {
                    sLogger.info("[proguard] missing proguard from " + androidDependency.getResolvedCoordinates());
                }
            }
        }
    }

    private static void addChildDependency(BundleItem bundleItem, Input input,
                                           Map<BundleInfo, AwbTransform> bundleInfoAwbTransformMap) throws IOException {

        List<String>pkgNames = new ArrayList<>();

        input.getAwbBundles().forEach(awbTransform -> pkgNames.add(awbTransform.getAwbBundle().getPackageName()));

        sLogger.info("combine to proguard bundles:"+pkgNames.toString());

        List<AwbTransform> childTransforms = new ArrayList<>();

        sLogger.info("combine to proguard bundles:"+pkgNames.toString());

        for (BundleItem child : bundleItem.children) {
            if (!pkgNames.contains(child.bundleInfo.getPkgName())) {
                childTransforms.add(bundleInfoAwbTransformMap.get(child.bundleInfo));
            }else {
                sLogger.error(child.bundleInfo.getPkgName() +" in proguard bundles so discard from "+ bundleItem.bundleInfo.getPkgName()+"libraries...");
            }
            for (BundleInfo sub : child.circles) {
                if (!pkgNames.contains(sub.getPkgName())) {
                    childTransforms.add(bundleInfoAwbTransformMap.get(sub));
                }else {
                    sLogger.error(sub.getPkgName() +" in proguard bundles so discard from "+ bundleItem.bundleInfo.getPkgName()+" libraries...");

                }
            }
        }

        List<AwbBundle> childBundles = new ArrayList<>();
        for (AwbTransform child : childTransforms) {
            input.getLibraries().addAll(child.getInputLibraries());
            //join
            childBundles.add(child.getAwbBundle());
        }
    }

    private static void addParentKeeps(BundleItem bundleItem, Input input, AwbTransform awbTransform,
                                       Map<BundleInfo, AwbTransform> bundleInfoAwbTransformMap,
                                       AppVariantContext appVariantContext) throws IOException {
        Set<AwbBundle> parentBundles = new HashSet<>();
        for (BundleItem parent : bundleItem.parents) {
            parentBundles.add(bundleInfoAwbTransformMap.get(parent.bundleInfo).getAwbBundle());
            for (BundleInfo sub : parent.circles) {
                parentBundles.add(bundleInfoAwbTransformMap.get(sub).getAwbBundle());
            }
        }
        if (!parentBundles.isEmpty()) {
            List<AwbBundle> bundles = new ArrayList<>(parentBundles);
            Collections.sort(bundles, new Comparator<AwbBundle>() {
                @Override
                public int compare(AwbBundle o1, AwbBundle o2) {
                    return o1.getName().compareTo(o2.getName());
                }
            });
            File keepFile = generateKeepFile(bundles,
                                             appVariantContext.getAwbProguardDir(
                                                 awbTransform.getAwbBundle()));
            input.getParentKeeps().add(keepFile);
        }
    }

    public static Set<String> getClassList(List<File> files) throws IOException {
        Set<String> sets = new HashSet<>();
        for (File file : files) {

            JarFile jarFile = new JarFile(file);
            Enumeration<JarEntry> entryEnumeration = jarFile.entries();

            while (entryEnumeration.hasMoreElements()) {
                JarEntry jarEntry = entryEnumeration.nextElement();
                if (null == jarEntry) {
                    continue;
                }
                String name = jarEntry.getName();
                if (name.endsWith(".class")) {
                    name = name.substring(0, name.length() - 6);
                    sets.add(name);
                }
            }
        }
        return sets;
    }

    public static void applyBundleKeepsV2(final AppVariantContext appVariantContext,
                                          ProGuardTransform proGuardTransform) throws IOException {

        File maindexkeep = generateBundleKeepCfg(appVariantContext);

        proGuardTransform.setConfigurationFiles(appVariantContext.getScope().getGlobalScope().getProject().files(maindexkeep));

    }

    @NotNull
    public static File generateBundleKeepCfg(AppVariantContext appVariantContext) throws IOException {
        AtlasDependencyTree dependencyTree = AtlasBuildContext.androidDependencyTrees.get(
            appVariantContext.getVariantConfiguration().getFullName());
        return generateKeepFile(dependencyTree.getAwbBundles(),
                                appVariantContext.getScope().getGlobalScope().getOutputsDir());
    }

    @NotNull
    private static File generateKeepFile(List<AwbBundle> awbBundles, File dir) throws IOException {

        KeepConverter refClazzContainer = new KeepConverter();
        for (AwbBundle awbBundle : awbBundles) {
            if (null != awbBundle.getKeepProguardFile() && awbBundle.getKeepProguardFile().exists()) {

                String json = FileUtils.readFileToString(awbBundle.getKeepProguardFile());
                Map<String, ClazzRefInfo> refClazzMap = JSON.parseObject(json,
                                                                         new TypeReference<Map<String, ClazzRefInfo>>
                                                                             () {});

                refClazzContainer.addRefClazz(refClazzMap);

            } else {
                sLogger.error(
                    "missing " + awbBundle.getKeepProguardFile().getAbsolutePath());
            }
        }

        File maindexkeep = new File(dir, "maindexkeep.cfg");
        FileUtils.writeLines(maindexkeep, refClazzContainer.convertToKeeplines());
        return maindexkeep;
    }

    public static void applyBundleKeeps(final AppVariantContext appVariantContext,
                                        ProGuardTransform proGuardTransform) {

        Set<File> proguardFiles = new HashSet<File>();

        GlobalScope globalScope = appVariantContext.getScope().getGlobalScope();
        //Add awb configuration
        AtlasDependencyTree dependencyTree = AtlasBuildContext.androidDependencyTrees.get(
            appVariantContext.getVariantConfiguration().getFullName());

        for (AwbBundle awbBundle : dependencyTree.getAwbBundles()) {
            if (null != awbBundle.getKeepProguardFile() && awbBundle.getKeepProguardFile().exists()) {
                proguardFiles.add(awbBundle.getKeepProguardFile());
            } else {
                appVariantContext.getProject().getLogger().error(
                    "missing " + awbBundle.getKeepProguardFile().getAbsolutePath());
            }
        }

        proGuardTransform.setConfigurationFiles(appVariantContext.getScope().getGlobalScope().getProject().files(proguardFiles));

    }

    public static File applyBundleInOutConfigration(final AppVariantContext appVariantContext,
                                                    ProGuardTransform proGuardTransform) {

        VariantScope variantScope = appVariantContext.getScope();

        GlobalScope globalScope = variantScope.getGlobalScope();
        File proguardOut = new File(Joiner.on(File.separatorChar)
                                        .join(String.valueOf(globalScope.getBuildDir()), FD_OUTPUTS, "mapping",
                                              variantScope.getVariantConfiguration().getDirName()));

        File awbInOutConfig = new File(proguardOut, "awb_inout_config.cfg");

        //Add awb configuration
        AtlasDependencyTree dependencyTree = AtlasBuildContext.androidDependencyTrees.get(
            variantScope.getVariantConfiguration().getFullName());

        if (dependencyTree.getAwbBundles().size() > 0) {

            BaseVariantOutput vod = (BaseVariantOutput) appVariantContext.getVariantOutputData().iterator().next();
            AppVariantOutputContext appVariantOutputContext = appVariantContext.getAppVariantOutputContext(ApkDataUtils.get(vod));
            File awbObfuscatedDir = new File(globalScope.getIntermediatesDir(),
                                             "/classes-proguard/" + variantScope.getVariantConfiguration()
                                                 .getDirName());
            AwbProguardConfiguration awbProguardConfiguration = new AwbProguardConfiguration(
                appVariantOutputContext.getAwbTransformMap().values(), awbObfuscatedDir, appVariantOutputContext);

            try {
                configs = awbProguardConfiguration.printConfigFile(awbInOutConfig);
            } catch (IOException e) {
                throw new GradleException("", e);
            }

            proGuardTransform.setConfigurationFiles(appVariantContext.getScope().getGlobalScope().getProject().files(awbInOutConfig));

        }

        return awbInOutConfig;
    }

    //TODO move
    //public static Set<String> blackList = Sets.newHashSet("com.alibaba:eaze","com.alibaba.mobileim:IMKit");
    public static void applyBundleProguardConfigration(final AppVariantContext appVariantContext,
                                                       ProGuardTransform proGuardTransform) {

        Set<String> blackList = appVariantContext.getAtlasExtension().getTBuildConfig()
            .getBundleProguardConfigBlackList();

        List<File> proguardFiles = new ArrayList<>();
        VariantScope variantScope = appVariantContext.getScope();
        for (AwbBundle awbBundle : AtlasBuildContext.androidDependencyTrees.get(
            variantScope.getVariantConfiguration().getFullName()).getAwbBundles()) {
            for (AndroidLibrary androidDependency : awbBundle.getAllLibraryAars()) {
                File proguardRules = androidDependency.getProguardRules();

                String groupName = androidDependency.getResolvedCoordinates().getGroupId() + ":" + androidDependency
                    .getResolvedCoordinates().getArtifactId();
                if (blackList.contains(groupName)) {
                    sLogger.info("[proguard] skip proguard from " + androidDependency.getResolvedCoordinates());
                    continue;
                }

                if (proguardRules.isFile()) {
                    proguardFiles.add(proguardRules);
                    sLogger.warn("[proguard] load proguard from " + androidDependency.getResolvedCoordinates());
                } else {
                    sLogger.info("[proguard] missing proguard from " + androidDependency.getResolvedCoordinates());
                }
            }
        }

        proGuardTransform.setConfigurationFiles(appVariantContext.getScope().getGlobalScope().getProject().files(proguardFiles));

    }

    public static File applyMapping(final AppVariantContext appVariantContext, ProGuardTransform proGuardTransform) {

        File mappingFile = null;
        if (null != appVariantContext.apContext.getApExploredFolder() && appVariantContext.apContext
            .getApExploredFolder().exists()) {
            mappingFile = new File(appVariantContext.apContext.getApExploredFolder(), "mapping.txt");
        } else {
            mappingFile = new File(
                appVariantContext.getScope().getGlobalScope().getProject().getProjectDir(),
                "mapping.txt");
        }

        if (null != mappingFile && mappingFile.exists()) {
            proGuardTransform.applyTestedMapping(mappingFile);
            return mappingFile;
        }

        return null;

    }

}
